package com.cby.library.common.base

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders
import com.cby.library.common.base.callback.EmptyCallback
import com.cby.library.common.base.callback.ErrorCallback
import com.cby.library.common.base.callback.LoadingCallback
import com.cby.library.common.base.callback.TimeoutCallback
import com.cby.library.common.ext.observe
import com.cby.library.common.util.NetworkUtils
import com.kingja.loadsir.core.LoadService
import com.kingja.loadsir.core.LoadSir
import java.lang.reflect.ParameterizedType

abstract class BaseStateFragment<VM : BaseViewModel> : Fragment() {

    var loadService: LoadService<Any>? = null

    var viewModel: VM? = null


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        parseArgs()
    }

    open fun parseArgs() {

    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(getLayoutId(), container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initViewModel()
        initView(view)
        pageStatusPopulate()
        onDataInit()
    }


    private fun initViewModel() {
        viewModel = obtainViewModel()
        bindLiveData()
    }

    abstract fun bindLiveData()

    abstract fun initView(view: View)

    abstract fun onDataInit()


    private fun pageStatusPopulate() {
        if(needPageStatus()) {
            // Your can change the callback on sub thread directly.
            val loadSir = LoadSir.Builder()
                .addCallback(LoadingCallback())
                .addCallback(EmptyCallback())
                .addCallback(ErrorCallback())
                .addCallback(TimeoutCallback())
                .setDefaultCallback(LoadingCallback::class.java)
                .build()
            loadService = loadSir.register(getPageTarget()) {
                reload()
            }

            observe(viewModel!!.pageStatusData) {
                when(it.status){
                    Status.LOADING -> loadService!!.showCallback(LoadingCallback::class.java)
                    Status.SUCCESS -> loadService!!.showSuccess()
                    Status.EMPTY -> loadService!!.showCallback(EmptyCallback::class.java)
                    Status.ERROR -> {
                        loadService!!.showCallback(if(NetworkUtils.isConnected) {
                            ErrorCallback::class.java
                        } else {
                            TimeoutCallback::class.java
                        })
                    }
                }

            }

        }
    }

    fun needPageStatus() = true

    abstract fun getLayoutId() : Int

    abstract fun getPageTarget() : Any

    open fun <VM> getGenericType(`object`: Any, index: Int): Class<VM> {
        return (`object`
            .javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[index] as Class<VM>
    }

    protected open fun obtainViewModel(): VM? {
        return try {
            val modelClass: Class<VM> = getGenericType(this, 0)
            ViewModelProviders.of(this).get(modelClass)
        } catch (e: ClassCastException) {
            //PrettyLogger.e(javaClass.simpleName, e.message)
            null
        }
    }

    abstract fun reload()
}